package com.example.app.Websocket;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.Camera1Enumerator;
import org.webrtc.CameraEnumerator;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RtpSender;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;
import java.util.ArrayList;
import java.util.List;
public class WebRTCManager {
    private static final String TAG = "WebRTCManager";
    private PeerConnectionFactory peerConnectionFactory;
    private PeerConnection peerConnection;
    private VideoCapturer videoCapturer;
    private SurfaceTextureHelper surfaceHelper;
    private EglBase eglBase;
    private RtpSender videoSender;
    private VideoTrack localVideoTrack;
    private AudioTrack localAudioTrack;
    private final Context context;
    private final String username;
    private String targetUser;
    private boolean isFrontCamera = true;
    private WebRTCListener listener;
    private WebSocketManager webSocketManager;
    private SurfaceViewRenderer localRender;
    private SurfaceViewRenderer remoteRender;
    public interface WebRTCListener {
        void onRemoteStreamAdded();
        void onCallReceived(String fromUser);
        void onConnectionEstablished();
        void onConnectionClosed();
        void onError(String error);
    }
    public void setListener(WebRTCListener webRTCListener){
        this.listener=webRTCListener;
    }
    public WebRTCManager(Context context, String username, WebRTCListener listener) {
        this.context = context.getApplicationContext();
        this.username = username;
        this.listener = listener;
        initializePeerConnectionFactory();
        setupWebSocket();
    }
    private void initializePeerConnectionFactory() {
        eglBase = EglBase.create();
        PeerConnectionFactory.InitializationOptions options = PeerConnectionFactory.InitializationOptions.builder(context).createInitializationOptions();
        PeerConnectionFactory.initialize(options);
        peerConnectionFactory = PeerConnectionFactory.builder().setVideoEncoderFactory(new DefaultVideoEncoderFactory(
                        eglBase.getEglBaseContext(),
                        true,
                        true)).setVideoDecoderFactory(new DefaultVideoDecoderFactory(eglBase.getEglBaseContext())).createPeerConnectionFactory();
    }
    private void setupWebSocket() {
        webSocketManager = new WebSocketManager(StaticData.RemoteHOSTS, username);
//        webSocketManager = new WebSocketManager("wss://192.168.43.241:443/VideoChatServerBaseWebRTC", username);
        webSocketManager.setMessageListener(new WebSocketManager.OnWebSocketMessageListener() {
            @Override
            public void onMessageReceived(JSONObject message) {
                handleWebSocketMessage(message);
            }
            @Override
            public void onConnectionOpen() {
                Log.d(TAG, "WebSocket connected");
            }
            @Override
            public void onConnectionClosed() {
                listener.onConnectionClosed();
            }
        });
        webSocketManager.connect();
    }
    public void initializeVideo(SurfaceViewRenderer local, SurfaceViewRenderer remote) {
        this.localRender = local;
        this.remoteRender = remote;
        localRender.init(eglBase.getEglBaseContext(), null);
        remoteRender.init(eglBase.getEglBaseContext(), null);
    }
    public void startCall(String target) {
        if (peerConnection != null) {
            hangup();
        }
        this.targetUser = target;
        createPeerConnection();
        startLocalCapture();
        sendJsonMessage("call_start", targetUser, null);
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            createOffer();
        }, 1000);
    }
    private void createPeerConnection() {
        List<PeerConnection.IceServer> iceServers = new ArrayList<>();
        iceServers.add(PeerConnection.IceServer.builder("stun:117.50.221.81:3478").createIceServer());
        iceServers.add(PeerConnection.IceServer.builder("turn:117.50.221.81:3478").setUsername("username").setPassword("password").createIceServer());
        PeerConnection.RTCConfiguration config = new PeerConnection.RTCConfiguration(iceServers);
        peerConnection = peerConnectionFactory.createPeerConnection(config, new PeerConnectionObserver() {
            @Override
            public void onIceCandidate(IceCandidate iceCandidate) {
                sendJsonMessage("_ice", targetUser, iceCandidate);
            }
            @Override
            public void onAddStream(MediaStream mediaStream) {
                if (mediaStream.videoTracks.size() > 0) {
                    mediaStream.videoTracks.get(0).addSink(remoteRender);
                }
                listener.onRemoteStreamAdded();
            }
            @Override
            public void onIceConnectionChange(PeerConnection.IceConnectionState newState) {
                if (newState == PeerConnection.IceConnectionState.DISCONNECTED) {
                    listener.onConnectionClosed();
                }
            }
        });
    }
    private void startLocalCapture() {
        try {
            videoCapturer = createCameraCapturer(isFrontCamera);
            VideoSource videoSource = peerConnectionFactory.createVideoSource(false);
            surfaceHelper = SurfaceTextureHelper.create("CaptureThread", eglBase.getEglBaseContext());
            videoCapturer.initialize(surfaceHelper, context, videoSource.getCapturerObserver());
            videoCapturer.startCapture(640, 480, 30);
            localVideoTrack = peerConnectionFactory.createVideoTrack("video", videoSource);
            localVideoTrack.addSink(localRender);
            AudioSource audioSource = peerConnectionFactory.createAudioSource(new MediaConstraints());
            localAudioTrack = peerConnectionFactory.createAudioTrack("audio", audioSource);
            if (peerConnection != null) {
                videoSender = peerConnection.addTrack(localVideoTrack);
                peerConnection.addTrack(localAudioTrack);
            }
        } catch (Exception e) {
            listener.onError("Failed to start local capture: " + e.getMessage());
        }
    }
    public void switchCamera() {
        isFrontCamera = !isFrontCamera;
        try {
            if (videoCapturer != null) {
                videoCapturer.stopCapture();
                videoCapturer.dispose();
            }
            if (surfaceHelper != null) {
                surfaceHelper.dispose();
            }
            videoCapturer = createCameraCapturer(isFrontCamera);
            VideoSource newVideoSource = peerConnectionFactory.createVideoSource(false);
            surfaceHelper = SurfaceTextureHelper.create("CaptureThread", eglBase.getEglBaseContext());
            videoCapturer.initialize(surfaceHelper, context, newVideoSource.getCapturerObserver());
            videoCapturer.startCapture(640, 480, 30);
            VideoTrack newVideoTrack = peerConnectionFactory.createVideoTrack("video", newVideoSource);
            newVideoTrack.addSink(localRender);
            if (videoSender != null) {
                boolean success = videoSender.setTrack(newVideoTrack, true);
                if (success) {
                    localVideoTrack = newVideoTrack;
                }
            } else if (peerConnection != null) {
                videoSender = peerConnection.addTrack(newVideoTrack);
            }
        } catch (Exception e) {
            listener.onError("Failed to switch camera: " + e.getMessage());
        }
    }
    private VideoCapturer createCameraCapturer(boolean isFront) {
        CameraEnumerator enumerator = new Camera1Enumerator(false);
        String[] deviceNames = enumerator.getDeviceNames();
        for (String deviceName : deviceNames) {
            if (isFront && enumerator.isFrontFacing(deviceName)) {
                return enumerator.createCapturer(deviceName, null);
            } else if (!isFront && enumerator.isBackFacing(deviceName)) {
                return enumerator.createCapturer(deviceName, null);
            }
        }
        return enumerator.createCapturer(deviceNames[0], null);
    }
    private void handleWebSocketMessage(JSONObject message) {
        try {
            String type = message.getString("type");
            String fromUser = message.getString("fromUser");
            String msg = message.optString("msg", "");
            switch (type) {
                case "call_start":
                    listener.onCallReceived(fromUser); // 触发接听对话框
                    break;
                case "offer":
                    handleOffer(message);
                    break;
                case "answer":
                    handleAnswer(message);
                    break;
                case "_ice":
                    handleIceCandidate(message);
                    break;
                case "hangup":
                    hangup();
                    break;
                case "call_back":
                    handleCallBack(message, fromUser);
                    break;
            }
        } catch (JSONException e) {
            listener.onError("WebSocket message error: " + e.getMessage());
        }
    }
    private void handleOffer(JSONObject json) throws JSONException {
        SessionDescription offer = new SessionDescription(
                SessionDescription.Type.OFFER,
                json.getString("sdp"));
        peerConnection.setRemoteDescription(new SimpleSdpObserver() {
            @Override
            public void onSetSuccess() {
                createAnswer();
            }
        }, offer);
    }
    private void createAnswer() {
        MediaConstraints constraints = new MediaConstraints();
        constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
        constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
        peerConnection.createAnswer(new SimpleSdpObserver() {
            @Override
            public void onCreateSuccess(SessionDescription sessionDescription) {
                peerConnection.setLocalDescription(new SimpleSdpObserver(), sessionDescription);
                sendJsonMessage("answer", targetUser, sessionDescription);
            }
        }, constraints);
    }
    private void handleAnswer(JSONObject json) throws JSONException {
        SessionDescription answer = new SessionDescription(
                SessionDescription.Type.ANSWER,
                json.getString("sdp"));
        peerConnection.setRemoteDescription(new SimpleSdpObserver(), answer);
    }
    private void handleIceCandidate(JSONObject json) throws JSONException {
        IceCandidate candidate = new IceCandidate(
                json.getString("sdpMid"),
                json.getInt("sdpMLineIndex"),
                json.getString("candidate"));
        if (peerConnection != null) {
            peerConnection.addIceCandidate(candidate);
        }
    }
    private void handleCallBack(JSONObject json, String fromUser) throws JSONException {
        String msg = json.getString("msg");
        if (msg.equals("1")) {
            if (peerConnection != null) {
                createOffer();
            }
        } else {
            hangup();
        }
    }
    public void createOffer() {
        MediaConstraints constraints = new MediaConstraints();
        constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
        constraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
        peerConnection.createOffer(new SimpleSdpObserver() {
            @Override
            public void onCreateSuccess(SessionDescription sessionDescription) {
                peerConnection.setLocalDescription(new SimpleSdpObserver(), sessionDescription);
                sendJsonMessage("offer", targetUser, sessionDescription);
            }
        }, constraints);
    }
    public void sendJsonMessage(String type, String toUser, Object data) {
        webSocketManager.sendJsonMessage(type, toUser, data);
    }
    public void hangup() {
        if (peerConnection != null) {
            peerConnection.close();
            peerConnection.dispose();
            peerConnection = null;

        }
        if (localVideoTrack != null) {
            localVideoTrack.dispose();
            localVideoTrack = null;
        }
        if (videoCapturer != null) {
            try {
                videoCapturer.stopCapture();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            videoCapturer.dispose();
            videoCapturer = null;
        }
        if (surfaceHelper != null) {
            surfaceHelper.dispose();
            surfaceHelper = null;
        }
        sendJsonMessage("hangup", targetUser, null);
        targetUser = null;
        if (listener != null) {
            listener.onConnectionClosed();
        }
    }
    public void destroy() {
        hangup();
        if (webSocketManager != null) {
            webSocketManager.disconnect();
        }
        PeerConnectionFactory.stopInternalTracingCapture();
        PeerConnectionFactory.shutdownInternalTracer();
    }
    public void acceptCall(String fromUser) {
        this.targetUser = fromUser;
        createPeerConnection();
        startLocalCapture();
        sendJsonMessage("call_back", targetUser, "1"); // 发送确认接听的消息
    }
    public void rejectCall(String fromUser) {
        sendJsonMessage("call_back", fromUser, "0");

        hangup();
    }
}